package com.googlecode.yoohoo.xmppcore.protocol;

import java.util.StringTokenizer;

import com.googlecode.yoohoo.utils.Utils;

public class JabberId {
	private String node;
	private String domain;
	private String resource;
	private String bareId;
	
	public JabberId() {}
	
	public JabberId(String domain) {
		this.domain = domain;
	}
	
	public JabberId(String node, String domain) {
		this.node = node;
		this.domain = domain;
	}
	
	public JabberId(String node, String domain, String resource) {
		this.node = node;
		this.domain = domain;
		this.resource = resource;
	}
	
	public String getNode() {
		return node;
	}
	
	public void setNode(String node) {
		this.node = node;
		bareId = null;
	}
	
	public String getDomain() {
		return domain;
	}
	
	public void setDomain(String domain) {
		this.domain = domain;
		bareId = null;
	}
	
	public String getResource() {
		return resource;
	}
	
	public void setResource(String resource) {
		this.resource = resource;
	}
	
	private void fromJidString(String jid) {
		if (jid.indexOf("@") == -1) {
			if (jid.indexOf("/") != -1)
				throw new InvalidJabberIdException();
			
			domain = jid;
		} else {
			StringTokenizer atTokenizer = new StringTokenizer(jid, "@");
			if (atTokenizer.countTokens() != 2)
				throw new InvalidJabberIdException();
			
			node = atTokenizer.nextToken();
			String domainAndResource = atTokenizer.nextToken();
			
			if (domainAndResource.indexOf("/") == -1) {
				domain = domainAndResource;
			} else {
				StringTokenizer slashTokenizer = new StringTokenizer(domainAndResource, "/");
				if (slashTokenizer.countTokens() != 2)
					throw new InvalidJabberIdException();
				
				domain = slashTokenizer.nextToken();
				resource = slashTokenizer.nextToken();
			}
		}
		
		try {
			validateJabberId();
		} catch (IllegalArgumentException e) {
			throw new InvalidJabberIdException(e);
		}		
	}
	
	public static JabberId parseJidString(String jid) {
		JabberId jabberId = new JabberId();
		jabberId.fromJidString(jid);
		
		return jabberId;
	}
	
	private void validateJabberId() {
		//(rfc3920 3.1)
		if (node != null && node.length() > 1023)
			throw new IllegalArgumentException("Node identifier of JID mustn't be more than 1023 bytes in length");
		if (domain != null && domain.length() > 1023)
			throw new IllegalArgumentException("Domain identifier of JID mustn't be more than 1023 bytes in length");
		if (resource != null && resource.length() > 1023)
			throw new IllegalArgumentException("Resource identifier of JID mustn't be more than 1023 bytes in length");
		
		// TODO JID format validation
	}

	@Override
	public String toString() {
		validateJabberId();
		
		StringBuilder builder = new StringBuilder();
		
		if (node != null)
			builder.append(node).append("@");
		builder.append(domain);
		if (resource != null)
			builder.append("/").append(resource);
		
		return builder.toString();
	}
	
	@Override
	public int hashCode() {
		int hashCode = domain.hashCode();
		
		if (node != null)
			hashCode += node.hashCode();
		
		if (resource != null)
			hashCode += resource.hashCode();
		
		return hashCode;
	}
	
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof JabberId))
			return false;
		
		JabberId other = (JabberId)obj;
		
		return Utils.equalsEvenNull(this.node, other.node) &&
				Utils.equalsExceptNull(this.domain, other.domain) &&
				Utils.equalsEvenNull(this.resource, other.resource);
	}
	
	public boolean isSameEntity(JabberId other) {
		if (this.domain == null || !this.domain.equals(other.domain))
			return false;
		
		return Utils.equalsEvenNull(this.node, other.node);
	}
	
	public String getBareIdString() {
		if (domain == null)
			throw new IllegalStateException("Null domain");
		
		if (bareId == null) {
			if (node == null)
				bareId = domain;
			else
				bareId = node + "@" + domain;	
		}
		
		return bareId;
	}
}
